package top.mcwebsite.playandroid.common.list

import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.LazyListState
import androidx.compose.foundation.lazy.itemsIndexed
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.paging.LoadState
import androidx.paging.compose.LazyPagingItems
import top.mcwebsite.playandroid.common.anim.JumpBall
import top.mcwebsite.playandroid.common.network.ApiException
import top.mcwebsite.playandroid.common.network.BizApiException
import top.mcwebsite.playandroid.common.network.unknown
import top.mcwebsite.playandroid.common.uiWidget.DefaultLoadingMore
import top.mcwebsite.playandroid.common.uiWidget.EmptyPage
import top.mcwebsite.playandroid.common.uiWidget.ErrorModel
import top.mcwebsite.playandroid.common.uiWidget.ErrorPage
import top.mcwebsite.playandroid.lib.mvi.model.Async


// TODO remove retry
// TODO common empty page
// TODO common loading page
// TODO common loading error
@Composable
fun <T : Any> EasyLazyListPageColumn(
    modifier: Modifier = Modifier,
    lazyPagingItems: LazyPagingItems<T>,
    state: LazyListState = rememberLazyListState(),
    retry: (() -> Unit)? = null,
    loading: @Composable () -> Unit = {
        Box(modifier = Modifier.fillMaxSize()) {
            JumpBall(modifier = Modifier.align(Alignment.Center))
        }
    },
    emptyPage: @Composable () -> Unit = {
        EmptyPage()
    },
    errorPage: @Composable (Throwable) -> Unit = {
        if (it is ApiException) {
            ErrorPage(errorModel = ErrorModel(it) {
                retry?.invoke()
            })
        }
    },
    loadingMore: @Composable () -> Unit = {
        DefaultLoadingMore()
    },
    loadingMoreError: @Composable (Throwable) -> Unit,
    content: @Composable (index: Int, item: T) -> Unit
) {
    if (lazyPagingItems.loadState.refresh == LoadState.Loading) {
        loading()
        return
    } else if (lazyPagingItems.loadState.refresh is LoadState.Error) {
        errorPage((lazyPagingItems.loadState.refresh as LoadState.Error).error)
        return
    } else if (lazyPagingItems.loadState.refresh is LoadState.NotLoading && lazyPagingItems.itemCount == 0) {
        emptyPage()
        return
    }
    LazyColumn(
        modifier = modifier,
        state = state,
    ) {
        items(count = lazyPagingItems.itemCount) { index ->
            lazyPagingItems[index]?.let {
                content(index, it)
            }
        }

        if (lazyPagingItems.loadState.append == LoadState.Loading) {
            item {
                loadingMore()
            }
        }

        if (lazyPagingItems.loadState.append is LoadState.Error) {
            item {
                loadingMoreError((lazyPagingItems.loadState.append as LoadState.Error).error)
            }
        }
    }
}

@Composable
fun <T> EasyLazyListPageColumn(
    async: Async<List<T>>,
    modifier: Modifier = Modifier,
    state: LazyListState = rememberLazyListState(),
    loading: @Composable () -> Unit = {
        Box(modifier = Modifier.fillMaxSize()) {
            JumpBall(modifier = Modifier.align(Alignment.Center))
        }
    },
    emptyPage: @Composable () -> Unit = {
        EmptyPage()
    },
    retry: (() -> Unit)? = null,
    errorPage: @Composable (Throwable) -> Unit = {
        if (it is ApiException) {
            ErrorPage(errorModel = ErrorModel(it) {
                retry?.invoke()
            })
        }
    },
    content: @Composable (Int, T) -> Unit
) {
    when (async) {
        is Async.Loading -> {
            loading()
        }

        is Async.Failed -> {
            errorPage(async.e ?: BizApiException.unknown(async.errorMsg))
        }

        is Async.Success -> {
            if (async.data.isEmpty()) {
                emptyPage()
            } else {
                LazyColumn(
                    modifier = modifier,
                    state = state,
                ) {
                    itemsIndexed(async.data) { index, item ->
                        content(index, item)
                    }
                }
            }
        }

        Async.UnInitialization -> {

        }
    }
}


